#pragma once

#include "Alloc.hh"

#include <cassert>
#include <new> // placement new

namespace snow
{

template <class T>
class Allocator
{
public:
    using value_type = T;
    using pointer = T *;
    using const_pointer = const T *;
    using reference = T &;
    using const_reference = const T &;
    using size_type = size_t;
    using difference_type = ptrdiff_t;

public:
    static T *allocate() { return (T *)Alloc::allocate(sizeof(T)); }
    static T *allocate(size_t n) { return (T *)Alloc::allocate(sizeof(T) * n); }
    static void deallocate(T *p) { Alloc::deallocate(p, sizeof(T)); }
    static void deallocate(T *p, size_t n)
    {
        if (0 == n) {
            return;
        }
        Alloc::deallocate(p, sizeof(T) * n);
    }

    static void construct(T *p) { new (p) T(); }
    static void construct(T *p, const T &value) { new (p) T(value); }
    static void destroy(T *p) { p->~T(); }
    static void destroy(T *first, T *last)
    {
        for (; first != last; ++first) {
            first->~T();
        }
    }
};

} // namespace snow